AI编程范式调研
总览中文入门文章:SDD 之外是 Harness 吗?
一个 Harness 资源参考仓库:awesome-harness-engineering
1.1 Vibe Coding
文章推荐
[ ] Vibe Coding in Practice: Motivations, Challenges, and a Future Outlook:学术界关于 Vibe Coding 的深度综述论文。理性地总结了 Vibe Coding 在提升心流、降低门槛上的巨大优势,以及它在测试缺失、代码质量失控上的原罪。
[ ] Good Vibrations? A Qualitative Study of Co-Creation, Communication, Flow, and Trust in Vibe Coding:从开发者体验出发,重点看协作、信任、流畅感、调试和 code review 负担。它的结论很适合补齐“Vibe Coding 为什么爽、但为什么会失控”。
1.2 SDD
文章推荐
这篇文章主要介绍了规格驱动开发(Spec-driven development, SDD)这一AI辅助软件工程新实践,阐述了它通过将清晰的软件规格说明(Spec)作为Prompt来驱动AI生成高质量代码,从而解决“氛围编码(Vibe coding)”带来的无序与代码不可维护问题。
- [ ] GitHub Spec Kit 官方工具文档:关于 SDD 开发的一个好的落地实践,使用
Spec -> Plan -> Tasks -> Implement流程。
- [ ] GitHub Spec Kit 官方工具文档:关于 SDD 开发的一个好的落地实践,使用
1.3 Harness
- 文章推荐
- [x] Anthropic: Effective harnesses for long-running agents:Anthropic 官方团队分享的 Harness 实践,设计初始化智能体(设定功能列表的 JSON 文件与环境)和编码智能体(单任务增量开发、利用 Git 提交和自动化测试保持环境干净)的“双智能体”协作方案,成功解决了长时运行 AI 智能体(Long-running agents)在跨多上下文窗口任务中容易“急于求成”或“过早宣布胜利”的失败模式。
- [ ] Addy Osmani: Agent Harness Engineering:Google Chrome 团队工程师写的技术博客。从纯粹的软件工程视角,深度剖析了 Harness 内部的 Hooks(钩子机制)、验证循环的具体做法。
- [ ] Harness Engineering for AI Coding Agents (Augment Code):补充了前沿大厂的 Monorepo 治理案例(例如 OpenAI 如何用 88 个 AGENTS.md 协作管理庞大的代码库),提供更宏观的 Harness 工业化实践视角。
- [ ] Anthropic: Harness design for long-running application development 这篇更偏“怎么设计 harness”。一个核心观点是:harness 的每个组件都在编码“模型自己做不到什么”,所以要不断压力测试这些假设;能简化就简化;必要时一次只删一个组件去看效果。这个思路很适合你理解“为什么 harness 比 prompt 更重要”。
1.4 好的实践
一个 Java 的 Agents.md 关于代码规范的模板,示范了如何把团队的 Java 规范给喂给 AI ,可以在此基础上,做自己的全局代码规范文档。
markdown## Code Fromatting - Indentation: 4 spaces. - Blank Lines: Use to separate logical blocks of code. - Line Length: Maximum 120 characters. - Use IntelliJ IDEA default code style for Java. ## Java Style - Use UTF-8 encoding. - Use descriptive names for classes, methods, and variables. - Avoid `var` keyword, prefer explicit types. - All method parameters should be `final`. - All variables should be declared as `final` where possible. - Preference for immutability: - Avoid mutations of objects, specially when using for-each loops or Stream API using `forEach()`. - Avoid magic numbers and strings; use constants instead. - Check emptiness and nullness before operations on collections and strings. - Avoid methods using `throws` clause; prefer unchecked exceptions. - Avoid comments. - Comments could be applied for: cron expressions, Regex patterns, TODOs or given/when/then separation in tests. - Use `@Override` annotation when overriding methods. - Avoid Objects.*isNull() and Objects.*nonNull() for one or two variables; prefer direct null checks for better performance. - Wrap multiple conditions in a boolean variable for better readibility - Prefer early returns. - Avoid else statements when not necessary and try early returns. ## Lombok Annotations - Use `@RequiredArgsConstructor` from Lombok for dependency injection via constructor. - Use `@Slf4j` from Lombok for logging. - Use `@Builder(setterPrefix = "with"))` for complex object creation. - Avoid `@Data` annotation; prefer `@Getter` and `@Setter` for granular control. ## Annotations - **`@Service`**: For business logic classes. - **`@Repository`**: For data access classes that extend JPA repositories or interact with the database. - **`@RestController`**: For web controllers. - **`@Component`**: For generic Spring components. - **`@Configuration`**: For Spring configuration classes. - **`@Autowired`**: Prefer constructor injection for production code and field injection only for tests. - **`@ConfigurationProperties`**: For binding related properties avoid multiple `@Value` annotations. From more than 2 properties, consider using this annotation. - **`@Transactional`**: Only Service classes should be annotated with @Transactional at class level to avoid transaction management in each method. - **`@Validated`**: To enable Bean Validation in method parameters or classes. - **`@PreAuthorize`**: at the controller layer when using Spring Security to enforce method-level security. - Circular dependencies should be avoided. Avoid `@Order` annotation for dependency resolution. ## Mappers(As a development team choose MapStruct or strictly static Mappers) **Use MapStruct** - MapFor mapping between DTOs and entities. - Define mapper interfaces with `@Mapper` annotation. - Use `@Mapping` annotation for custom field mappings. - Use `componentModel = "spring"` to allow Spring to manage mapper instances. - Mapper should have as suffix `Mapper` (e.g., `UserMapper`). - Name mapper methods clearly (e.g., `toDto`, `toEntity`). - Example Mapper Interface: ```java @Mapper(componentModel = "spring") public interface UserMapper { @Mapping(source = "email", target = "emailAddress") UserDTO toDto(User user); @Mapping(source = "emailAddress", target = "email") User toEntity(UserDTO userDto); }- For testing mappers, use
Mappers.getMapper(UserMapper.class)to get an instance of the mapper.
Use Static Mappers
Define a private constructor to prevent instantiation with
UnsupportedOperationException("This class should never be instantiated").Use static methods for mapping between DTOs and entities.
Name mapper methods clearly (e.g.,
toDto,toEntity).Example Static Mapper Class:
javapublic class UserMapper { private UserMapper() { throw new UnsupportedOperationException("This class should never be instantiated"); } public static UserDTO toDto(final User user) { if (user == null) { return null; } return UserDTO.builder() .withId(user.getId()) .withEmailAddress(user.getEmail()) .build(); } public static User toEntity(final UserDTO userDto) { if (userDto == null) { return null; } return User.builder() .withId(userDto.getId()) .withEmail(userDto.getEmailAddress()) .build(); } }
Exception Handling
- Custom Exceptions: Create custom domain exception classes extending
RuntimeException. - Global Exception Handler: Use
@ControllerAdviceand@ExceptionHandlerto handle exceptions globally. - HTTP Status Codes: Map exceptions to appropriate HTTP status codes in REST controllers.
- Error Response Structure: Define a consistent error response structure
Testing
- Use JUnit 5 for unit and integration testing.
- Use Mockito for mocking dependencies in unit tests.
- Use
@WebMvcTest(ControllerClass.class)for testing Spring MVC controllers. - Use
@SpringBootTestfor integration tests that require the Spring context. - Use
given/when/thenstructure in test methods for clarity. - Method naming could follow snake_case or camelCaset convention for test methods (e.g.,
get_user_by_id_ok,get_user_by_id_not_found_ko). - Avoid reflection in tests.
- Avoid business logic in tests; focus on behavior verification.
Logging
- Use
@Slf4jannotation from Lombok for logging to avoid boilerplate code with Logger instances. - Log at appropriate levels:
DEBUG,INFO,WARN,ERROR. - Include contextual information in logs (e.g., request IDs, user IDs).
- Avoid logging sensitive information.
- Use structured logging for better log management.
- Format log messages with placeholders (e.g.,
{}) instead of string concatenation. - Logging info code could follow this template: log.info("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: response: {}, userId: {}", body, userId);
- Logging error code could follow this template: log.error("[MicroserviceName/ModuleName] - API-CALL/METHOD/ACTION: errorMessage: {}, userId: {}", errorMessage, userId);
来源:[Agents.md Guide for Java and Spring Boot Developers](https://josealopez.dev/en/blog/agents-md-java-spring-boot)- For testing mappers, use
一个有趣的在开始 coding 之前的拆解任务的 prompt
markdown# 🎓 角色设定:顶级编程实战课程设计师 (Curriculum Designer) 你目前是 Codecademy / Udacity 级别的高级课程研发总监。你极其擅长将复杂的真实商业项目,拆解为**面向“高智商但缺乏工程经验的新手程序员”的渐进式实战闯关教程**。 我是一名**不编写代码的产品经理兼课程考官**。我将向你提供一份商业产品需求(PRD)。 你的唯一任务是:基于我的需求,逆向工程设计出一套**《项目全栈落地闯关大纲 (Quest Map)》**。 这套大纲的目的是指导一名“天才学生”一步步从零搭建出生产级应用。你**绝对不要**输出任何具体的业务代码,你的工作是“写教案”。 ## 🧠 核心设计哲学 (Codecademy 模式) 为了让学生在开发中不迷失方向,且每次提交都能获得正向反馈,你设计的关卡必须遵循以下原则: 1. **原子化递进 (Micro-Steps)** - 绝对禁止宏大的任务(例如:“开发购物车模块” 是绝对错误的)。 - 必须拆解为极微小的动作(例如:“关卡 1:渲染购物车静态 UI 骨架”、“关卡 2:编写计算总价的本地纯函数”、“关卡 3:将本地状态接入全局状态管理库”)。 - **严格防超纲**:必须明确限制学生在当前关卡**禁止**做什么(例如:“本关只画 UI,严禁连接数据库”)。 2. **黑盒验收标准 (Black-box Acceptance Criteria)** - 因为我(考官)不看代码,所以每个关卡的通关条件必须是**肉眼可见的物理反馈**。 - 验收标准必须具体到操作步骤。例如:“在终端运行命令 X”、“在浏览器点击按钮 Y”、“在控制台观察到日志 Z”、“在数据库面板看到新增记录 W”。 - 如果某个后端关卡没有界面,必须要求学生写一个简单的 API 测试脚本或明确要求输出特定的终端日志,以便我验证。 3. **现代工程化与“胶水编程” (Modern Glue Coding)** - 引导学生使用成熟的现代技术栈和第三方 SaaS 服务(如 Clerk 鉴权、Supabase 数据库、Vercel 部署等)。 - 把“阅读并接入某第三方轮子的 API”单独设计为一个关卡。 ## 📋 《闯关大纲》标准输出格式 在理清我的需求后,你必须按以下结构输出 Markdown 格式的教案: ## 项目需求 _(总结PRD,简述本项目的具体需求)_ ## 阶段 [X]:[阶段名称] (例如:阶段 1:脚手架与静态路由搭建) _(简述本阶段的学习目标和工程意义)_ ### 🟢 Quest [X.1]:[关卡名称] - **🎯 关卡目标**:一句话描述本关要完成的单一任务。 - **🛠️ 推荐工具/轮子**:本关建议使用的库或命令。 - **🚫 边界限制 (防超纲)**:明确告诉学生本关**不需要**关心什么逻辑。 - **✅ 考官验收标准 (PM Checklist)**: - [ ] 测试动作 1:(例如:在根目录执行 `npm run dev`) - [ ] 预期结果 1:(例如:浏览器打开 `localhost:3000`,看到包含 "Hello World" 的白屏页面) - [ ] 测试动作 2:... - [ ] 预期结果 2:... _(以此类推,穷尽整个产品的所有功能)_ ## 🚦 沟通与设计流程 1. **需求反问**:收到我的 PRD 后,先不要急于出大纲。如果需求中缺失了关键的技术选型约束(比如:想部署在哪?用什么数据库?是否需要移动端适配?),请先向我提问确认。 2. **大纲草案**:确认无误后,输出完整的《闯关大纲》。 3. **配合修改**:如果我认为某些关卡的“验收标准”不够直观,或者关卡跨度太大,我会提出意见,你必须重新拆分该关卡。 4. **抹除修正痕迹**:对大纲发起新的否定/修改/调整指令时,在生成的新的回复中,应直接、流畅地呈现,仿佛它从一开始就是如此。严禁在修正后的大纲中出现引述、反驳或对比旧大纲的语句。输出的大纲必须是正式版本,而不是一篇“被反复修改过”的大纲。一个我个人认为比较好的任务清单结构,可以用该结构替换掉上面的父任务拆分为的子任务的结构
json{ "category": "functional", "description": "New chat button creates a fresh conversation", "steps": [ "Navigate to main interface", "Click the 'New Chat' button", "Verify a new conversation is created", "Check that chat area shows welcome state", "Verify conversation appears in sidebar" ], "passes": false }一个我个人认为比较好的 Agents.md 组织的结构,目标:实现渐进式披露,实现较好的上下文管理
my-project/ ├── AGENTS.md # L1:< 100 行,纯索引 ├── init.sh # 环境苏醒脚本 └── docs/ ├── 1-standards/ # L2:长期稳定,规定"怎么写" │ ├── coding-standards.md # 你已有的 Java 规范 │ ├── database-conventions.md │ ├── testing-standards.md │ └── security-guidelines.md │ ├── 2-constraints/ # L2:约束型架构规则(非叙述型) │ ├── layer-dependencies.md # 分层依赖规则(什么层能调什么层) │ ├── api-contracts.md # API 设计约定、错误码结构 │ └── adr/ # Architecture Decision Records │ └── 001-use-mapstruct.md │ └── 3-tasks/ # L3:高频动态,规定"现在干什么" ├── CURRENT_PLAN.md # 当前大任务执行计划(Agent 可更新) └── specs/ # 具体任务 Spec(用完归档) └── TASK-101-signin.md